package vinnichenko.lab3;

/**Own packages*/
import vinnichenko.lab3.exception.*;

/** Import required java libraries*/
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

import org.w3c.dom.*;
import org.xml.sax.*;

import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;

/**Error handler servlet. Used to show errors.*/
public class ErrorHandler extends HttpServlet {

    /**UID*/
    private static final long serialVersionUID = 8L;
 
    /**Declaration and creation logger.*/
    static Logger logger = Logger.getLogger(ErrorHandler.class);

    /**Method to handle GET method request.
     * @param request - servlet request.
     * @param response - servlet response.
     * @throws ServletException, IOException.
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException{

        /** Analyze the servlet exception: get throwable object, status code and servlet name.*/
        Throwable throwable = (Throwable)request.getAttribute("javax.servlet.error.exception");
        Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
        String servletName = (String)request.getAttribute("javax.servlet.error.servlet_name");

        if (servletName == null){
            servletName = "Unknown";
        }

        /** Set response content type*/
        response.setContentType("text/html");
 
        PrintWriter out = response.getWriter();
        
        try{
            /** Get a DocumentBuilderFactory for creating
             * a DocumentBuilder (i.e., an XML parser)*/
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            /**Get a DocumentBuilder for building the DOM tree*/
            DocumentBuilder builder = factory.newDocumentBuilder();

            /**Create a new Document (empty DOM tree)*/
            Document messageDocument = builder.newDocument();

            /**Prepare XML document with all information about exception.*/
            Element error_info = messageDocument.createElement( "error_information" );
            Element temp = messageDocument.createElement( "error_code" );
            temp.appendChild( messageDocument.createTextNode( String.valueOf(statusCode) ) );
            error_info.appendChild( temp );
            temp = messageDocument.createElement( "servlet_name" );
            temp.appendChild( messageDocument.createTextNode( servletName ) );
            error_info.appendChild( temp );
            temp = messageDocument.createElement( "exception_message" );
            temp.appendChild( messageDocument.createTextNode( StackWriter.getFullStackTrace( throwable ) ) );
            error_info.appendChild( temp );
            temp = messageDocument.createElement( "exception_type" );
            temp.appendChild( messageDocument.createTextNode( throwable.getClass().getName() ) );
            error_info.appendChild( temp );

            messageDocument.appendChild( error_info );

            /**Open InputStream for XSL document*/
            InputStream xslStream = getServletContext().getResourceAsStream( "/error.xsl" );

            /**Transform XML document using XSLT*/
            XMLTransformer.transform( messageDocument, xslStream, out );
        }catch ( ParserConfigurationException pcException ) { 
            /**If catch exception, then write it into log.*/
            logger.error(StackWriter.getFullStackTrace( pcException ));
            /**catch XML parser exception and throw it.*/
            throw new ServletException( pcException );
        }catch ( XSLTTransformingException e ) { 
            logger.error(StackWriter.getFullStackTrace( e ));
            getServletContext().setAttribute("javax.servlet.error.exception", (Throwable)e );
            throw new ServletException( e );
        }

        /**Closing output stream.*/
        out.flush();
        out.close();
    }
    
    /** Method to handle POST method request.
     * @param request - servlet request.
     * @param response - servlet response.
     * @throws ServletException, IOException.
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        
        doGet(request, response);
    }
}